package com.qyer.search.storm.util;

import com.qyer.search.storm.exception.DBException;
import com.qyer.search.storm.logging.InfoLogger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.concurrent.atomic.*;

import java.util.*;
import java.sql.*;
/**
 * Created by tangzheng on 16/1/11.
 */
public class CommonCityService implements Runnable {
  private InfoLogger dataLog;

  private volatile static CommonCityService singleton;
  private Map<Integer, String> cities;
  private Thread thread;
  private String dBurl;
  private String user;
  private String pass;
  private String sql;
  private Connection conn = null;

  private  AtomicBoolean _shutdown;

  private CommonCityService (Map<String, Object> config, String boltPrefix, String stormInfo){
    dataLog = new InfoLogger("/Data/search/CommonCityService/" + stormInfo +"_cityService", stormInfo + "_data");
    cities = new HashMap<>();
    _shutdown = new AtomicBoolean(false);

    dBurl = String.valueOf(config.get(boltPrefix + "db.city.url"));
    user = String.valueOf(config.get(boltPrefix + "db.city.user"));
    pass = String.valueOf(config.get(boltPrefix + "db.city.password"));
    sql = "select id,cityname from city where cityname != '';";

    try {
      Class.forName("com.mysql.jdbc.Driver");
      conn = java.sql.DriverManager.getConnection(dBurl, user, pass);
      Statement stmt = conn.createStatement();
      ResultSet res = stmt.executeQuery(sql);
      while (res.next()){
        cities.put(res.getInt(1), res.getString(2));
      }
    }catch (Exception e){
      dataLog.info("city map get failed,{}", e);
    }

    thread = new Thread(this, "cityService" + stormInfo);
    thread.start();

    dataLog.info("city service thread start.");
  }
  public static CommonCityService getInstance(Map<String, Object> config, String boltPrefix, String stormInfo) {
    if (singleton == null) {
      synchronized (CommonCityService.class) {
        if (singleton == null) {
          singleton = new CommonCityService(config, boltPrefix, stormInfo);
        }
      }
    }
    return singleton;
  }

  public String getCityName(int id){
    return cities.get(id);
  }
  public boolean isCity(int id){
    return cities.containsKey(id);
  }

  @Override public void run() {
    int seconds = 0;
    try {
      while (!_shutdown.get()) {
        checkConn();
        if(seconds == 300000) {
          Statement stmt = conn.createStatement();
          ResultSet res = stmt.executeQuery(sql);
          Map<Integer, String> _cities = new HashMap<>();
          while (res.next()) {
            _cities.put(res.getInt(1), res.getString(2));
          }
          cities = _cities;
          seconds = 0;
        }
        Thread.sleep(10000);
        seconds += 10000;
      }
    }catch (Exception e){
      dataLog.info("interrupt by {}", e);
    }
  }

  private void checkConn(){
    try {
      if((conn == null) || (!conn.isValid(1))){
        dataLog.info("mysqlconnection is invalid,rebuild follow.");

        Connection _tempConn = conn;
        this.conn = getConnection(dBurl, user, pass);
        if(_tempConn != null) {
          _tempConn.close();
          dataLog.info("close the past mysqlconnection.");
        }
      }else {
        dataLog.info("mysqlconnection is ok");
      }
    }catch (Exception e){
      e.printStackTrace();
      dataLog.info("mysqlconnection rebuild failed by {}.", e);
      dataLog.info("Exception:{},DB connection invalid.", e.getMessage());
    }
  }

  private Connection getConnection(String dBurl, String user, String pass){
    try {
      Class.forName("com.mysql.jdbc.Driver");
      return java.sql.DriverManager.getConnection(dBurl, user, pass);
    }catch (Exception e){
      dataLog.info("get mysql connection failed.Exception is {}", e);
      return null;
    }
  }

  public void shutdown(){

    if(_shutdown.compareAndSet(false, true)) {
      try {
        if (conn != null)
          conn.close();
      } catch (Exception e) {
        dataLog.info("during shutdown,mysql connection shutdown failed.");
      }
      thread.interrupt();
    }
  }


}
